package br.com.massai.model.entity;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.persistence.UniqueConstraint;

import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;

import br.com.massai.view.enums.Status;

@Entity
@Table(name = "DEPARTMENT", uniqueConstraints = @UniqueConstraint(columnNames={"CODE_EMP", "CODE_DEPARTMENT"}))
@NamedQueries({
	@NamedQuery(name = "Department.find", query = "SELECT d FROM Department d"),
	@NamedQuery(name = "Department.duplicate", query = "SELECT COUNT(d) FROM Department d WHERE d.codeEmp =:codeEmp AND d.codeDepartment =:codeDepartment"),
	@NamedQuery(name = "Department.count", query = "SELECT COUNT(d) FROM Department d")
})
public class Department extends GenericEntity {

	private static final long serialVersionUID = -8974882927850521342L;

	@Id
	@SequenceGenerator(name = "seqDepartment", sequenceName = "seq_department", allocationSize = 1)
	@GeneratedValue(generator = "seqDepartment", strategy = GenerationType.SEQUENCE)
	private Long id;

	@Column(name = "CODE_EMP", length = 5, columnDefinition = "VARCHAR(5)")
	private String codeEmp;

	@Column(name = "CODE_DEPARTMENT", length = 17, columnDefinition = "VARCHAR(14)")
	private String codeDepartment;

	@Column(name = "CODE_SIENGE", columnDefinition = "NUMERIC(9,0)")
	private Long codeSienge;

	@Column(name = "NAME_DEPARTMENT", length = 150, columnDefinition = "VARCHAR(150)")
	private String nameDepartment;

	@Column(name = "ALTERNATIVE_NAME", length = 200, nullable = false, columnDefinition = "VARCHAR(200)")
	private String alternativeName;

	@Enumerated(EnumType.STRING)
	@Column(name = "STATUS", columnDefinition = "CHAR(1)")
	private Status status;

	@ManyToOne(optional = true, fetch = FetchType.EAGER)
	@JoinColumn(name = "PRODUCTION_GROUP_ID", referencedColumnName = "ID")
	private ProductionGroup productionGroup;

	@ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.MERGE)
	@Fetch(FetchMode.JOIN)
	@JoinTable(name = "COLLABORATORS",
		joinColumns = @JoinColumn(name = "DEPARTMENT_ID", referencedColumnName = "ID"),
		inverseJoinColumns = @JoinColumn(name = "COLLABORATOR_ID", referencedColumnName = "ID"))
	private List<Collaborator> collaborators;
	
	@Column(name = "DELETED", columnDefinition = "BOOLEAN DEFAULT false")
	private boolean deleted;

	@Transient
	private boolean selected;
	
	public Department() {
		this.collaborators = new ArrayList<Collaborator>();
		this.selected = false;
		this.deleted = false;
	}

	@Override
	public Map<String, Object> getParameters() {
		super.clearParameters();

		if(this.codeEmp != null && !this.codeEmp.trim().isEmpty()){
			super.addClauseWhere("d.codeEmp =:codeEmp)", ConditionType.AND);
			super.addParameters("codeEmp", this.codeEmp);
		}

		if(this.codeDepartment != null && !this.codeDepartment.trim().isEmpty()){
			super.addClauseWhere("d.codeDepartment =:codeDepartment)", ConditionType.AND);
			super.addParameters("codeDepartment", this.codeDepartment);
		}

		if(this.codeSienge != null && this.codeSienge.intValue() > 0){
			super.addClauseWhere("d.codeSienge =:codeSienge)", ConditionType.AND);
			super.addParameters("codeSienge", this.codeSienge);
		}

		if(this.nameDepartment != null && !this.nameDepartment.trim().isEmpty()){
			super.addClauseWhere("LOWER(d.nameDepartment) LIKE LOWER(:nameDepartment)", ConditionType.AND);
			super.addParameters("nameDepartment", "%" + this.nameDepartment + "%");
		}
		
		if(this.alternativeName != null && !this.alternativeName.trim().isEmpty()){
			super.addClauseWhere("LOWER(d.alternativeName) LIKE LOWER(:alternativeName)", ConditionType.AND);
			super.addParameters("alternativeName", "%" + this.alternativeName + "%");
		}

		if(this.status != null){
			super.addClauseWhere("d.status =:status", ConditionType.AND);
			super.addParameters("status", this.status);
		}

		super.addClauseWhere("d.deleted =:deleted", ConditionType.AND);
		super.addParameters("deleted", false);

		return super.getParameters();
	}
	
	@Override
	public boolean equals(Object obj) {
		if(obj == null) return false;
		if(obj instanceof Department)
			if(((Department)obj).getId().equals(this.id)) return true;

		return false;
	}

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public String getCodeDepartment() {
		return codeDepartment;
	}

	public void setCodeDepartment(String codeDepartment) {
		this.codeDepartment = codeDepartment;
	}

	public Long getCodeSienge() {
		return codeSienge;
	}

	public void setCodeSienge(Long codeSienge) {
		this.codeSienge = codeSienge;
	}

	public String getNameDepartment() {
		return nameDepartment;
	}

	public void setNameDepartment(String nameDepartment) {
		this.nameDepartment = nameDepartment;
	}

	public Status getStatus() {
		return status;
	}

	public void setStatus(Status status) {
		this.status = status;
	}

	public ProductionGroup getProductionGroup() {
		return productionGroup;
	}

	public void setProductionGroup(ProductionGroup productionGroup) {
		this.productionGroup = productionGroup;
	}

	public List<Collaborator> getCollaborators() {
		return collaborators;
	}

	public void setCollaborators(List<Collaborator> collaborators) {
		this.collaborators = collaborators;
	}

	public boolean isSelected() {
		return selected;
	}

	public void setSelected(boolean selected) {
		this.selected = selected;
	}

	public String getCodeEmp() {
		return codeEmp;
	}

	public void setCodeEmp(String codeEmp) {
		this.codeEmp = codeEmp;
	}

	public String getAlternativeName() {
		return alternativeName;
	}

	public void setAlternativeName(String alternativeName) {
		this.alternativeName = alternativeName;
	}

	public boolean isDeleted() {
		return deleted;
	}

	public void setDeleted(boolean deleted) {
		this.deleted = deleted;
	}
}
